package com.kexio.websocket.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.WebSocketSession;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * WebSocket 会话管理服务
 * 
 * 管理用户的 WebSocket 会话，支持多租户环境。
 * 
 * @author Kexio Team
 */
@Service
public class WebSocketSessionService {

    private static final Logger log = LoggerFactory.getLogger(WebSocketSessionService.class);

    // 存储用户会话映射: tenantId:userId -> List<WebSocketSession>
    private final ConcurrentHashMap<String, CopyOnWriteArrayList<WebSocketSession>> userSessions = new ConcurrentHashMap<>();
    
    // 存储会话到用户的反向映射: sessionId -> tenantId:userId
    private final ConcurrentHashMap<String, String> sessionToUser = new ConcurrentHashMap<>();

    /**
     * 注册用户会话
     * 
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @param session WebSocket会话
     */
    public void registerUserSession(String tenantId, String userId, String sessionId, WebSocketSession session) {
        String userKey = buildUserKey(tenantId, userId);
        
        // 添加到用户会话映射
        userSessions.computeIfAbsent(userKey, k -> new CopyOnWriteArrayList<>()).add(session);
        
        // 添加到反向映射
        sessionToUser.put(sessionId, userKey);
        
        log.debug("注册用户会话: userKey={}, sessionId={}, 当前会话数={}", 
                userKey, sessionId, userSessions.get(userKey).size());
    }

    /**
     * 注销用户会话
     * 
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @param sessionId 会话ID
     */
    public void unregisterUserSession(String tenantId, String userId, String sessionId) {
        String userKey = buildUserKey(tenantId, userId);
        
        // 从用户会话映射中移除
        CopyOnWriteArrayList<WebSocketSession> sessions = userSessions.get(userKey);
        if (sessions != null) {
            sessions.removeIf(session -> session.getId().equals(sessionId));
            
            // 如果用户没有活跃会话，移除用户映射
            if (sessions.isEmpty()) {
                userSessions.remove(userKey);
            }
        }
        
        // 从反向映射中移除
        sessionToUser.remove(sessionId);
        
        log.debug("注销用户会话: userKey={}, sessionId={}, 剩余会话数={}", 
                userKey, sessionId, sessions != null ? sessions.size() : 0);
    }

    /**
     * 根据会话ID注销
     * 
     * @param sessionId 会话ID
     */
    public void unregisterSession(String sessionId) {
        String userKey = sessionToUser.get(sessionId);
        if (userKey != null) {
            String[] parts = userKey.split(":");
            if (parts.length == 2) {
                unregisterUserSession(parts[0], parts[1], sessionId);
            }
        }
    }

    /**
     * 获取用户的所有活跃会话
     * 
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @return 活跃会话列表
     */
    public List<WebSocketSession> getUserSessions(String tenantId, String userId) {
        String userKey = buildUserKey(tenantId, userId);
        CopyOnWriteArrayList<WebSocketSession> sessions = userSessions.get(userKey);
        
        if (sessions != null) {
            // 过滤掉已关闭的会话
            List<WebSocketSession> activeSessions = sessions.stream()
                    .filter(WebSocketSession::isOpen)
                    .collect(Collectors.toList());
            
            // 移除已关闭的会话
            sessions.removeIf(session -> !session.isOpen());
            
            return activeSessions;
        }
        
        return List.of();
    }

    /**
     * 获取租户下所有用户的活跃会话
     * 
     * @param tenantId 租户ID
     * @return 活跃会话列表
     */
    public List<WebSocketSession> getAllUserSessions(String tenantId) {
        return userSessions.entrySet().stream()
                .filter(entry -> entry.getKey().startsWith(tenantId + ":"))
                .flatMap(entry -> entry.getValue().stream())
                .filter(WebSocketSession::isOpen)
                .collect(Collectors.toList());
    }

    /**
     * 检查用户是否在线
     * 
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @return 是否在线
     */
    public boolean isUserOnline(String tenantId, String userId) {
        return !getUserSessions(tenantId, userId).isEmpty();
    }

    /**
     * 获取在线用户数量
     * 
     * @param tenantId 租户ID
     * @return 在线用户数量
     */
    public int getOnlineUserCount(String tenantId) {
        return (int) userSessions.keySet().stream()
                .filter(key -> key.startsWith(tenantId + ":"))
                .count();
    }

    /**
     * 获取总会话数量
     * 
     * @param tenantId 租户ID
     * @return 总会话数量
     */
    public int getTotalSessionCount(String tenantId) {
        return getAllUserSessions(tenantId).size();
    }

    /**
     * 清理已关闭的会话
     */
    public void cleanupClosedSessions() {
        log.debug("开始清理已关闭的会话");
        
        int cleanedCount = 0;
        
        for (CopyOnWriteArrayList<WebSocketSession> sessions : userSessions.values()) {
            int beforeSize = sessions.size();
            sessions.removeIf(session -> !session.isOpen());
            cleanedCount += (beforeSize - sessions.size());
        }
        
        // 移除空的用户映射
        userSessions.entrySet().removeIf(entry -> entry.getValue().isEmpty());
        
        // 清理反向映射
        sessionToUser.entrySet().removeIf(entry -> {
            String userKey = entry.getValue();
            CopyOnWriteArrayList<WebSocketSession> sessions = userSessions.get(userKey);
            return sessions == null || sessions.stream().noneMatch(session -> 
                    session.getId().equals(entry.getKey()) && session.isOpen());
        });
        
        if (cleanedCount > 0) {
            log.info("清理了 {} 个已关闭的会话", cleanedCount);
        }
    }

    /**
     * 构建用户键
     * 
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @return 用户键
     */
    private String buildUserKey(String tenantId, String userId) {
        return tenantId + ":" + userId;
    }

    /**
     * 获取统计信息
     */
    public WebSocketStats getStats() {
        int totalUsers = userSessions.size();
        int totalSessions = userSessions.values().stream()
                .mapToInt(List::size)
                .sum();
        
        return new WebSocketStats(totalUsers, totalSessions);
    }

    /**
     * WebSocket 统计信息
     */
    public static class WebSocketStats {
        private final int onlineUsers;
        private final int activeSessions;

        public WebSocketStats(int onlineUsers, int activeSessions) {
            this.onlineUsers = onlineUsers;
            this.activeSessions = activeSessions;
        }

        public int getOnlineUsers() {
            return onlineUsers;
        }

        public int getActiveSessions() {
            return activeSessions;
        }

        @Override
        public String toString() {
            return "WebSocketStats{" +
                    "onlineUsers=" + onlineUsers +
                    ", activeSessions=" + activeSessions +
                    '}';
        }
    }
}
